package com.kj.misc.web;

import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.google.common.collect.Maps;
import com.google.common.io.Files;
import com.ivan.toolkit.common.AnyResult;
import com.ivan.toolkit.common.Configs;
import com.kj.misc.domain.MiscConfig;
import com.kj.misc.domain.MiscFeshConfig.FeshEntry;
import com.kj.misc.domain.MiscFetcherConfig.FetcherEntry;
import com.kj.misc.domain.MiscFetcherConfig.ValueEntry;
import com.kj.misc.domain.MiscValue;
import com.kj.misc.domain.MiscValueTimestamp;
import com.kj.misc.service.MiscBoss;
import com.kj.misc.service.MiscData;
import com.kj.misc.service.MiscFetcher;
import com.kj.misc.service.MiscFetcherManager;
import com.kj.misc.service.MiscStorage;

import lombok.extern.log4j.Log4j2;

@Controller
@RequestMapping("/misc")
@ResponseBody
@Log4j2
public class MiscController {
	
	@Autowired
	private MiscBoss boss;
	
	@Autowired
	private MiscFetcherManager fetchers;
	
	@Autowired
	private MiscData data;
	
	@Autowired
	private MiscStorage storage;
	
	@RequestMapping(value="/dataString.do") 
	public AnyResult getDataString() {
		
		long now = System.currentTimeMillis();
		
		StringBuilder sb = new StringBuilder();
		Map<String, MiscValue> map = data.snapshot();
		map.forEach((s,d)->{
			sb
			.append(s)
			.append("=")
			.append(d.getValue())
			.append("[")
			.append((now - d.getBirth()))
			.append("ms]")
			.append("\r\n");
		});
		return AnyResult.success().data(sb.toString());
	}
	
	@RequestMapping(value="/fetcherString.do") 
	public AnyResult getFetcherString() {
		
		StringBuilder sb = new StringBuilder();
		List<MiscFetcher> list = fetchers.fetchers();
		list.forEach(f->{
			sb.append(f.formatState()).append("\r\n");
		});
		return AnyResult.success().data(sb.toString());

	}
	
	@RequestMapping(value="/fetcherEnable.do") 
	public AnyResult enableFetcher(String fetcherName, boolean enabled) {
		
		Optional<MiscFetcher> op = fetchers.getFetcherByName(fetcherName);
		op.ifPresent(f->{
			f.setEnabled(enabled);
		});
		
		return AnyResult.success();
	}
	
	@RequestMapping(value="/value.do") 
	public Map<String, MiscValueTimestamp> getValue(String keys) {
		long now = System.currentTimeMillis();
		Map<String, MiscValueTimestamp> result = Maps.newLinkedHashMap();
		Map<String, MiscValue> map =  data.valueByKeys(keys);
		map.forEach((k, v)->{
			result.put(k, new MiscValueTimestamp(now, v.getBirth(), v.getValue()));
		});
		return result;
	}
	
	@RequestMapping(value="/keys.do") 
	public List<String> getAllKeys() {
		return MiscConfig.getKeys(null);
	}
	
	@RequestMapping(value="/list.do") 
	public String[] listFiles(String key) {
		return storage.listDataFiles(key);
	}
	
	@RequestMapping(value="/history.do") 
	public List<MiscValueTimestamp> getHistory(String key, String filename) {
		return storage.read(key, filename);
	}
	
	@RequestMapping(value="/historyByDay.do") 
	public List<MiscValueTimestamp> getHistory(String key, int year, int month, int day) {
		String filename = String.format("%04d%02d%02d.csv", year, month, day);
		return storage.read(key, filename);
	}
	
	@RequestMapping(value="/historyToday.do") 
	public List<MiscValueTimestamp> getHistory(String key) {
		return storage.readByDay(key, System.currentTimeMillis());
	}
	
	@RequestMapping(value="/set_parameter.do")  
    public AnyResult updateParameter(String valueKey, String parameterKey, String parameterValue) { 
		if(fetchers.updateParameter(valueKey, parameterKey, parameterValue)) {
			return AnyResult.success();
		} else {
			return AnyResult.failure();
		}
    }  
	
	@RequestMapping(value="/parameter.do")  
    public AnyResult getParameter(String valueKey, String parameterKey) { 
		
		Optional<String> os = fetchers.getParameter(valueKey, parameterKey);
		
		if(os.isPresent()) {
			return AnyResult.success().data(os.get());
		} else {
			return AnyResult.failure();
		}
    }  
	
	

	@RequestMapping(value="/upload.do",method=RequestMethod.POST) 
	public AnyResult uploadConfig(@RequestParam("file") MultipartFile file, HttpServletRequest req) {
		
		try {
			
			File temp = new File(System.getProperty("java.io.tmpdir"), System.currentTimeMillis() + ".xml");
			if(!file.isEmpty()) {
				
				file.transferTo(temp);
				
				Configs.loadx(MiscConfig.class, temp, false).ifPresent(t-> {
					MiscConfig.instance.set(t);
				});
				
				temp.delete();
				
				new Thread(()-> boss.reset()).start();
				
			}
			
			return AnyResult.success();
		
		} catch(Exception e) {
			
			log.error("upload config file failed. ", e);
			
			return AnyResult.failure().message(e.getMessage());
			
		}
		
	}
	
	@RequestMapping(value="/config.do")  
    public void downloadConfig(HttpServletResponse response) { 
		
		response.setContentType("application/x-gzip"); 
        try {  
            response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("config.xml", "UTF-8"));  
            Files.copy(MiscConfig.instance.file(), response.getOutputStream());  
        } catch (IOException ex) {  
            ex.printStackTrace();  
        }  
		
    }  

	@RequestMapping(value="/sample.do")  
    public void downloadSample(HttpServletResponse response) { 
		
		MiscConfig config = new MiscConfig();

		FetcherEntry fe = new FetcherEntry();
		fe.setName("SAMPLE");
		config.getFetcherConfig().getFetchers().add(fe);
		
		ValueEntry ve = new ValueEntry();
		ve.setValueKey("D1");
		ve.setParameters("key1=value1,key2=value2");
		fe.getValues().add(ve);
		ve = new ValueEntry();
		ve.setValueKey("D2");
		ve.setParameters("key1=value1,key2=value2");
		fe.getValues().add(ve);
		
		config.getFusionConfig().setHeadKey("SAMPLE.D1");
		config.getFusionConfig().setTailKey("SAMPLE.D2");
		
		config.getFeshConfig().setPrefix("FESH");
		FeshEntry feshEntry = new FeshEntry();
		feshEntry.setName("DEMO");
		feshEntry.setFeshKey1("SAMPLE.D1");
		feshEntry.setFeshKey2("SAMPLE.D2");
		config.getFeshConfig().getFeshes().add(feshEntry);		
		
		File temp = new File(System.getProperty("java.io.tmpdir"), "sample.xml");
		Configs.save(config, temp, false);
		
		
		response.setContentType("application/x-gzip"); 
        try {  
            response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("sample.xml", "UTF-8"));  
            Files.copy(temp, response.getOutputStream());  
        } catch (IOException ex) {  
            ex.printStackTrace();  
        }  
		
        temp.delete();
    }  

}
